﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using BlueLotus7.ArchiveSystem.Common;
using BlueLotus7.ArchiveSystem.Interfaces;
using BlueLotus7.Eden.Service.BusinessLayer;
using BlueLotus7.Eden.Service.Properties;

namespace BlueLotus7.Eden.Service
{
    public class ArchiveSystemCommonService : IArchiveSystemCommonService
    {
        protected BaseDataAdapter dataAdapter = null;
        protected bool throwException = false;

        protected const string objectName_domainScope = "domainScope";
        protected const string objectName_domainScopeUser = "domainScopeUser";
        protected const string objectName_monitorClient = "monitorClient";
        protected const string objectName_Name = "Name";
        protected const string exceptionNullValue = "<null>";

        #region Constructor

        public ArchiveSystemCommonService()
        {
            dataAdapter = new BaseDataAdapter();
        }

        public ArchiveSystemCommonService(bool throwException)
            : this()
        {
            this.throwException = throwException;
        }

        #endregion

        #region Domain Scope

        /// <summary>
        /// Adds or updates <c>DomainScope</c> object.
        /// </summary>
        /// <param name="domainScope"></param>
        public Guid? AddOrUpdateDomainScope(DomainScope domainScope)
        {
            Guid? result = null;
            try
            {
                ValidateNullObject(domainScope, objectName_domainScope);
                ValidateNullObject(domainScope.Name, objectName_Name);
                result = dataAdapter.AddOrUpdateDomainScope(domainScope);
                if (result == null)
                {
                    Global.Logger.LogException(new Exception("No data updated for entity: " + domainScope.Name));
                }
            }
            catch (Exception ex)
            {
                Exception exception = new Exception(LogMessageHelper.GetFailedOperationMessage("add or update", "domain scope"), ex);
                Global.Logger.LogException(exception, domainScope);
                if (this.throwException)
                {
                    throw exception;
                }
            }
            return result;
        }

        /// <summary>
        /// Query <c>DomainScope</c> objects.
        /// </summary>
        /// <param name="domainScopeType"></param>
        /// <param name="keywords"></param>
        /// <returns></returns>
        public List<DomainScope> QueryDomainScopeList(DomainScopeType? domainScopeType, string keywords)
        {
            List<DomainScope> result = new List<DomainScope>();
            try
            {
                result = dataAdapter.QueryDomainScopes(domainScopeType, keywords);
            }
            catch (Exception ex)
            {
                Exception exception = new Exception(LogMessageHelper.GetFailedOperationMessage("query", "domain scopes", "type: " + (domainScopeType == null ? exceptionNullValue : domainScopeType.Value.ToString() + " , keywords: " + GetMajorIdentity(keywords))), ex);
                Global.Logger.LogException(exception);
                if (this.throwException)
                {
                    throw exception;
                }
            }
            return result;
        }

        /// <summary>
        /// Gets <c>DomainScope</c> object by key.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public DomainScope GetDomainScopeByKey(Guid key)
        {
            DomainScope scope = null;
            try
            {
                scope = dataAdapter.GetDomainScopeByKey(key);
            }
            catch (Exception ex)
            {
                Exception exception = new Exception(LogMessageHelper.GetFailedOperationMessage("get", "domain scope", key.ToString()), ex);
                Global.Logger.LogException(exception);
                if (this.throwException)
                {
                    throw exception;
                }
            }

            return scope;
        }

        /// <summary>
        /// Gets <c>DomainScope</c> object by code.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public DomainScope GetDomainScopeByCode(string code)
        {
            DomainScope scope = null;

            if (!string.IsNullOrWhiteSpace(code))
            {
                try
                {
                    scope = dataAdapter.GetDomainScopeByCode(code.Trim());
                }
                catch (Exception ex)
                {
                    Exception exception = new Exception(LogMessageHelper.GetFailedOperationMessage("get", "domain scope", code), ex);
                    Global.Logger.LogException(exception);
                    if (this.throwException)
                    {
                        throw exception;
                    }
                }
            }

            return scope;
        }

        #endregion

        #region Domain Scope User

        /// <summary>
        /// Adds or updates <c>DomainScopeUser</c> object.
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public Guid? AddOrUpdateScopeUser(DomainScopeUser user)
        {
            Guid? newKey = null;
            try
            {
                ValidateNullObject(user, objectName_domainScopeUser);
                ValidateNullObject(user.ThirdPartyIdentity, objectName_Name);
                newKey = dataAdapter.AddOrUpdateDomainScopeUser(user);
                if (newKey == null)
                {
                    Global.Logger.LogException(new Exception("No data updated for entity: " + user.ThirdPartyIdentity));
                }
            }
            catch (Exception ex)
            {
                Exception exception = new Exception(LogMessageHelper.GetFailedOperationMessage("add or update", "domain scope user"), ex);
                Global.Logger.LogException(exception, user);
                if (this.throwException)
                {
                    throw exception;
                }
            }

            return newKey;
        }

        /// <summary>
        /// Query <c>DomainScopeUser</c> objects.
        /// </summary>
        /// <param name="scopeKey"></param>
        /// <param name="identityKeyword"></param>
        /// <returns></returns>
        public List<DomainScopeUser> QueryDomainScopeUsers(Guid? scopeKey, string identityKeyword)
        {
            List<DomainScopeUser> result = new List<DomainScopeUser>();
            try
            {
                result = dataAdapter.QueryDomainScopeUser(scopeKey, identityKeyword);
            }
            catch (Exception ex)
            {
                Exception exception = new Exception(LogMessageHelper.GetFailedOperationMessage("query", "domain scope users", "scope: " + (scopeKey == null ? exceptionNullValue : scopeKey.Value.ToString() + " , keywords: " + GetMajorIdentity(identityKeyword))), ex);
                Global.Logger.LogException(exception);
                if (this.throwException)
                {
                    throw exception;
                }
            }

            return result;
        }

        /// <summary>
        /// Gets <c>DomainScopeUser</c> entity.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public DomainScopeUser GetDomainScopeUserByKey(Guid key)
        {
            DomainScopeUser result = null;
            try
            {
                result = dataAdapter.GetDomainScopeUserByKey(key);
            }
            catch (Exception ex)
            {
                Exception exception = new Exception(LogMessageHelper.GetFailedOperationMessage("get", "domain scope user", key.ToString()), ex);
                Global.Logger.LogException(exception);
                if (this.throwException)
                {
                    throw exception;
                }
            }

            return result;
        }

        #endregion

        #region Client

        /// <summary>
        /// Creates <c>ClientHearbeat</c>
        /// </summary>
        /// <param name="clientKey"></param>
        /// <param name="lastSettingStamp"></param>
        /// <returns></returns>
        public bool CreateClientHeartbeat(Guid clientKey, DateTime lastSettingStamp)
        {
            bool result = false;
            try
            {
                result = dataAdapter.CreateClientHeartbeat(clientKey, lastSettingStamp);
            }
            catch (Exception ex)
            {
                Exception exception = new Exception(LogMessageHelper.GetFailedOperationMessage("create", "client heartbeat", clientKey.ToString()), ex);
                Global.Logger.LogException(exception);
                if (this.throwException)
                {
                    throw exception;
                }
            }

            return result;
        }

        /// <summary>
        /// Query <c>ClientHearbeat</c>
        /// </summary>
        /// <param name="clientKey"></param>
        /// <param name="topCount"></param>
        /// <returns></returns>
        public List<ClientHeartbeat> QueryClientHearbeat(Guid? clientKey, int topCount)
        {
            List<ClientHeartbeat> result = new List<ClientHeartbeat>();
            try
            {
                result = dataAdapter.QueryClientHearbeat(clientKey, topCount);
            }
            catch (Exception ex)
            {

                Exception exception = new Exception(LogMessageHelper.GetFailedOperationMessage("query", "client heartbeat"), ex);
                Global.Logger.LogException(exception, new { clientKey = clientKey, topCount = topCount });
                if (this.throwException)
                {
                    throw exception;
                }
            }

            return result;
        }

        /// <summary>
        /// Gets <c>MonitorClient</c>
        /// </summary>
        /// <returns></returns>
        public List<MonitorClient> GetMonitorClients()
        {
            List<MonitorClient> result = new List<MonitorClient>();
            try
            {
                result = dataAdapter.GetMonitorClients();
            }
            catch (Exception ex)
            {
                Exception exception = new Exception(LogMessageHelper.GetFailedOperationMessage("get", "monitor clients"), ex);
                Global.Logger.LogException(exception);
                if (this.throwException)
                {
                    throw exception;
                }
            }

            return result;
        }

        /// <summary>
        /// Gets <c>MonitorClient</c> by key
        /// </summary>
        /// <param name="monitorClientKey"></param>
        /// <returns></returns>
        public MonitorClient GetMonitorClientByKey(Guid monitorClientKey)
        {
            MonitorClient client = null;
            try
            {
                client = dataAdapter.GetMonitorClientByKey(monitorClientKey);
            }
            catch (Exception ex)
            {
                Exception exception = new Exception(LogMessageHelper.GetFailedOperationMessage("get", "monitor client", monitorClientKey.ToString()), ex);
                Global.Logger.LogException(exception);
                if (this.throwException)
                {
                    throw exception;
                }
            }

            return client;
        }

        /// <summary>
        /// Adds <c>MonitorClient</c>
        /// </summary>
        /// <param name="client"></param>
        /// <returns></returns>
        public Guid? AddMonitorClient(MonitorClient client)
        {
            Guid? result = null;
            try
            {
                ValidateNullObject(client, objectName_monitorClient);
                ValidateNullObject(client.Name, objectName_Name);
                result = dataAdapter.AddMonitorClient(client);
            }
            catch (Exception ex)
            {
                Exception exception = new Exception(LogMessageHelper.GetFailedOperationMessage("add or update", "monitor client"), ex);
                Global.Logger.LogException(exception, client);
                if (this.throwException)
                {
                    throw exception;
                }
            }

            return result;
        }

        /// <summary>
        /// Updates <c>MonitorClient</c>
        /// </summary>
        /// <param name="client"></param>
        /// <returns></returns>
        public bool UpdateMonitorClient(MonitorClient client)
        {
            bool result = false;
            try
            {
                ValidateNullObject(client, objectName_monitorClient);
                ValidateNullObject(client.Name, objectName_Name);
                result = dataAdapter.UpdateMonitorClient(client);
            }
            catch (Exception ex)
            {
                Exception exception = new Exception(LogMessageHelper.GetFailedOperationMessage("add or update", "monitor client"), ex);
                Global.Logger.LogException(exception, client);
                if (this.throwException)
                {
                    throw exception;
                }
            }

            return result;
        }

        #endregion

        #region Monitor Task

        public Guid? AddOrUpdateMonitorTask(MonitorTask task)
        {
            return null;
        }

        public List<ReportableTask> GetMonitorTaskByClientKey(Guid clientKey, bool includeDisabled)
        {
            return null;
        }

        public ReportableTask GetMonitorTaskByKey(Guid key)
        {
            return null;
        }

        public List<ReportableTask> QueryMonitorTasks(string name, Guid? clientKey, MonitorTask.TaskExecutionType? executionType, string thirdPartyIdentity, bool? isNightOperationOnly, bool? isDisabled)
        {
            return null;
        }


        #endregion

        #region Utility

        protected static void ValidateNullObject(object obj, string objectName)
        {
            if (obj == null)
            {
                Global.Logger.LogException(new Exception("Null object: " + objectName));
            }
        }

        protected static void ValidateNullOrEmptyString(string stringObject, string objectName)
        {
            if (stringObject == null || string.IsNullOrWhiteSpace(stringObject.Trim()))
            {
                Global.Logger.LogException(new Exception("Null or empty string: " + objectName));
            }
        }

        protected static string GetMajorIdentity(string identity)
        {
            return string.IsNullOrWhiteSpace(identity) ? exceptionNullValue : identity;
        }

        #endregion

    }
}
